#pragma once

#define SCA_CHECK 0x01
#define SCA_MIGRATE_DISABLE 0x02
#define SCA_MIGRATE_ENABLE 0x04
#define SCA_USER 0x08

struct affinity_context
{
    const struct cpumask *new_mask;
    struct cpumask *user_mask;
    unsigned int flags;
};


struct sched_class
{
    void (*init_class)(void);
    void (*init_rq)(struct rq *rq);

    void (*enqueue_task)(struct rq *rq, struct task_struct *p, int flags);
    bool (*dequeue_task)(struct rq *rq, struct task_struct *p, int flags);
    void (*yield_task)(struct rq *rq);
    bool (*yield_to_task)(struct rq *rq, struct task_struct *p);
    void (*wakeup_preempt)(struct rq *rq, struct task_struct *p, int flags);

    int (*balance)(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
    struct task_struct *(*pick_task)(struct rq *rq);
    /*
     * Optional! When implemented pick_next_task() should be equivalent to:
     *
     *   next = pick_task();
     *   if (next) {
     *       put_prev_task(prev);
     *       set_next_task_first(next);
     *   }
     */
    struct task_struct *(*pick_next_task)(struct rq *rq, struct task_struct *prev);

    void (*put_prev_task)(struct rq *rq, struct task_struct *p, struct task_struct *next);
    void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);

    void (*task_dead)(struct task_struct *p);
    void (*task_tick)(struct rq *rq, struct task_struct *p, int queued);

    void (*switching_to)(struct rq *this_rq, struct task_struct *task);
    void (*switched_from)(struct rq *this_rq, struct task_struct *task);
    void (*switched_to)(struct rq *this_rq, struct task_struct *task);
    void (*prio_changed)(struct rq *this_rq, struct task_struct *task,
                         int oldprio);
    void (*reweight_task)(struct rq *this_rq, struct task_struct *task,
                          const struct load_weight *lw);
    void (*update_curr)(struct rq *rq);

#ifdef CONFIG_SMP
    int (*select_task_rq)(struct task_struct *p, int task_cpu, int flags);
    void (*task_woken)(struct rq *this_rq, struct task_struct *task);

    void (*set_cpus_allowed)(struct task_struct *p, struct affinity_context *ctx);

	void (*rq_online)(struct rq *rq);
	void (*rq_offline)(struct rq *rq);
#endif
};

#define DEFINE_SCHED_CLASS(name) \
    const struct sched_class name##_sched_class

extern const struct sched_class **__sched_class_highest(void);
extern const struct sched_class **__sched_class_lowest(void);
extern const struct sched_class **__sched_class_at(const struct sched_class *sc);

extern const struct sched_class rt_sched_class;
extern const struct sched_class idle_sched_class;
extern const struct sched_class fair_sched_class;
